home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / Developers / Little Smalltalk v3.1.4 / Smalltalk Source / tclwin.st < prev    next >
Encoding:
Text File  |  1995-01-26  |  24.2 KB  |  1,018 lines  |  [TEXT/KAHL]

  1. * ***
  2. * tclwin.st
  3. *
  4. * Classes to create and control the windowing interface
  5. *
  6. * Julian Barkway (c) September 1994 All rights reserved. 
  7. *
  8. * (Based on stdwin.st by Timothy Budd)
  9. *
  10. * v3.1.0 - Initial release
  11. * v3.1.1 - Changed to ensure correct system menu highlighting 
  12. *           when no windows are open.
  13. * v3.1.2 - No longer crashes when 'printer print:' invoked with no Workspace.
  14. *         - Changed to allow the Workspace window to be restored after 
  15. *          being closed.
  16. *        - Pixel line length can now be specified for text-based panes.
  17. *        - Sundry tidying-up of code.
  18. * v3.1.3 - Pop-up menu objects removed from global menus array. Global added to 
  19. *          track pop-up menu numbers.
  20. *        - Added Smalltalk: getVersion to return the version number as a string.
  21. *        - Menus now referred to by direct pointers to their internal representation
  22. *          instead of array indices.
  23. *
  24. * ***
  25. Class UserInterface Object saveWS nextItemNumber itemList        " - changed for v3.1.2 "
  26. Class Window Object number title menus size position panes paneNumber mainPane
  27. Class     WorkspaceWindow Window                   " - class added for v3.1.2 "
  28. Class WindowPane Object panePtr number type lineLength parentWindow bounds sizing b1Action b2Action b1DoubleClick
  29. Class    TextPane WindowPane text fontName fontSize typeFace selectRange
  30. Class          SelectListPane TextPane selection 
  31. Class    GraphicsPane WindowPane
  32. Class EventManager Process responses
  33. Class Menu Object menuPtr number title itemtitles items enablestatus numItems
  34. Class     PopUpMenu Menu
  35. Class Cursor Object cursPtr
  36.  
  37. Methods Window 'all'
  38.     new
  39.         title      <- ''.
  40.         menus      <- List new.
  41.         panes      <- Array new: 15.
  42.         paneNumber <- 0.
  43.         ^ self allocateSlot
  44. |
  45.     allocateSlot
  46.         " Allocate a slot in the 'windows' global array. Moved out of 'new'
  47.           to allow standalone access for v3.1.2 "
  48.         (1 to: 15) do: [:i | (windows at: i) isNil
  49.             ifTrue: [ windows at: i put: self.
  50.                     number <- i.  ^ self ] 
  51.         ]
  52. |
  53.     attachPane: pane
  54.         paneNumber <- paneNumber + 1.
  55.         panes at: paneNumber put: pane.
  56.         mainPane <- pane.
  57.         ^ paneNumber
  58. |
  59.     attachMenu: menu
  60.         menus addLast: menu.
  61.         <162 number 2 (menu menuPtr)>
  62. |
  63.     detachMenu: menu
  64.         <162 number 3 (menu menuPtr)>
  65. |
  66.     activate
  67.         activeWindow <- self
  68. |
  69.     deactivate
  70.         ^ nil
  71. |
  72.     mainPane
  73.         ^ mainPane
  74. |
  75.     panes
  76.         ^ panes
  77. |
  78.     drawEvent
  79.     " if no panes, do nothing otherwise let each pane draw itself "
  80.         (paneNumber == 0) ifTrue: [
  81.             ^ nil
  82.         ]
  83.         ifFalse: [
  84.             (1 to: paneNumber) do: [ :i |
  85.                 (panes at: i) draw
  86.             ]
  87.         ]
  88. |
  89.     mouseMoveTo: mouseLocation
  90.         " mouse moved with button down "
  91.         ^ nil
  92. |
  93.     mouseDownAt: mouseLocation button: theButton
  94.     " if no panes, do nothing otherwise let the appropriate pane handle the event "
  95.         (paneNumber == 0) ifTrue: [
  96.             ^ nil
  97.         ]
  98.         ifFalse: [
  99.             (1 to: paneNumber) do: [ :i |
  100.                  ((panes at: i) mouseDownAt: mouseLocation button: theButton) 
  101.                 ifTrue: [
  102.                     ^ nil
  103.                 ]
  104.             ].
  105.             ^ nil
  106.         ]
  107. |
  108.     mouseUpAt: mouseLocation
  109.         " mouse up "
  110.         ^ nil
  111. |
  112.     command: n
  113.         (n = 1) ifTrue: [ self close ]
  114. |
  115.     moved
  116.         position <- <161 number 7>
  117. |
  118.     reSized
  119.         size <- <161 number 6>
  120. |
  121.     position
  122.         ^ position
  123. |
  124.     size
  125.         ^ size
  126. |
  127.     number
  128.         ^ number
  129. |
  130.     title
  131.         ^ title
  132. |
  133.     open
  134.         " open our window, unless already opened "
  135.         <160 number 1 title 0>.
  136.         menus do: [:m | <162 number 2 (m menuPtr)> ].
  137.         userInterface addToWindowsMenu: self.
  138.         self reSized.
  139.         self moved
  140. |
  141.     openAt: aPosition withSize: aSize
  142.         " open our window, unless already opened "
  143.         <160 number 2 title 0 (aPosition x) (aPosition y) (aSize x) (aSize y)>.
  144.         self open
  145. |
  146.     select
  147.         <161 number 8>.
  148.         self activate
  149. |
  150.     wantsSave
  151.         ^ <161 number 9>
  152. |
  153.     charTyped: c
  154.         smalltalk beep
  155. |
  156.     title: text
  157.         title <- text.
  158.         <161 number 10 title>
  159. |
  160.     close
  161.         " close up shop "
  162.         <161 number 1>.
  163.         windows at: number put: nil.
  164.         userInterface removeFromWindowsMenu: self
  165. |
  166.     saveState
  167.         " Save the state of system items (i.e. text that has been 
  168.           entered by the user) which are not represented by LSt objects " 
  169.         panes do: [:p | 
  170.             p notNil ifTrue: [ 
  171.                 p saveState
  172.             ] 
  173.         ]
  174. |
  175.     restoreState
  176.         " Restore the state of this window and all its panes 
  177.           after loading a new image file "
  178.         self openAt: position withSize: size.
  179.         panes do: [:p | 
  180.             p notNil ifTrue: [ 
  181.                 p restoreState
  182.             ] 
  183.         ]
  184. ]
  185.  
  186. Methods WorkspaceWindow 'all'                " Class added for v3.1.2 "
  187.     new
  188.     | maxW maxH |
  189.         super new.
  190.         maxW <- (smalltalk getMaxScreenArea) right.
  191.         maxW <- 500 min: (maxW - 50).
  192.         maxH <- (smalltalk getMaxScreenArea) bottom.
  193.         maxH <- 300 min: (maxH - 50).
  194.         self title: 'Workspace';
  195.             openAt: (0@0) withSize: (maxW@maxH). " (0@0) = system places window "
  196.         TextPane new; 
  197.             boundsFrom: (-1 @ -1) to: (size + (1 @ 1)); 
  198.             attachTo: self;
  199.             print: 'Welcome to Little Smalltalk ' , (smalltalk getVersion) , 
  200.                     newLine , newLine.
  201. |
  202.     close
  203.         self saveState.
  204.         userInterface saveWorkspace.
  205.         super close.
  206. |
  207.     restoreWorkspace
  208.         self allocateSlot.
  209.         self restoreState.
  210. ]
  211.  
  212. Methods WindowPane 'all'
  213.     new
  214.         bounds     <- Rectangle new.
  215.         lineLength <- 0.
  216. |
  217.                     " Sizing options: 0 - axis is rigid, 1 - axis is elastic "
  218.     attachTo: aWindow withType: theType andSizing: aPoint
  219.         type    <- theType.
  220.         sizing  <- aPoint.
  221.         panePtr <- < 168 1 (aWindow number) theType 
  222.                         (bounds upperLeft x) 
  223.                         (bounds upperLeft y)
  224.                         (bounds bottomRight x)
  225.                         (bounds bottomRight y) 
  226.                         (aPoint x) (aPoint y) 
  227.                         lineLength >.
  228.         number       <- (aWindow attachPane: self).
  229.         parentWindow <- aWindow.
  230.         ^ panePtr
  231. |
  232.     boundsFrom: topLeft to: bottomRight
  233.         bounds upperLeft: topLeft.
  234.         bounds bottomRight: bottomRight 
  235. |
  236.     type: theType            " 1 - text, 2 - select, 3 - graphics "
  237.         type <- theType
  238. |
  239.     activate
  240.         ^ nil
  241. |
  242.     deactivate
  243.         ^ nil
  244. |
  245.     size
  246.         ^ <168 2 panePtr>
  247. |
  248.     position
  249.         ^ nil
  250. |
  251.     reSized
  252.         ^ nil
  253. |
  254.     draw
  255.         ^ nil
  256. |
  257.     mouseDownAt: mouseLocation button: theButton
  258.     " Changed to allow double clicks for v3.1.2 "
  259.         (bounds contains: mouseLocation) ifFalse: [
  260.             ^ false
  261.         ]
  262.         ifTrue: [
  263.             (theButton == 1) ifTrue: [
  264.                 (eventManager isDoubleClick) ifTrue: [
  265.                     (b1DoubleClick notNil) ifTrue: [
  266.                         b1DoubleClick value: mouseLocation
  267.                     ]
  268.                 ]
  269.                 ifFalse: [
  270.                     (b1Action notNil) ifTrue: [
  271.                         b1Action value: mouseLocation
  272.                     ]
  273.                 ]
  274.             ].
  275.             (theButton == 2) ifTrue: [
  276.                 (b2Action notNil) ifTrue: [
  277.                     b2Action value: mouseLocation
  278.                 ]
  279.             ].
  280.             ^ true
  281.         ]
  282. |
  283.     button1Action: aBlock
  284.         b1Action <- aBlock
  285. |
  286.     button1DoubleClick: aBlock
  287.         b1DoubleClick <- aBlock
  288. |
  289.     button2Action: aBlock
  290.         b2Action <- aBlock
  291. |
  292.     saveState
  293.         " Handled by sub-classes "
  294.         ^ nil
  295. |
  296.     restoreState
  297.         " Handled by sub-classes "
  298.         ^ nil
  299. ]
  300.  
  301. Methods TextPane 'all'
  302.     isTextPane
  303.         ^ true
  304. |
  305.                                                         " Added for v3.1.2 "
  306.     attachTo: aWindow withSizing: aPoint andLineLength: anInteger
  307.         lineLength <- anInteger.
  308.         panePtr    <- super attachTo: aWindow withType: 1 andSizing: aPoint
  309. |
  310.     attachTo: aWindow withSizing: aPoint
  311.         lineLength <- 2000.
  312.         panePtr    <- super attachTo: aWindow withType: 1 andSizing: aPoint
  313. |
  314.     attachTo: aWindow
  315.         lineLength <- 2000.
  316.         panePtr    <- super attachTo: aWindow withType: 1 andSizing: (1@1)
  317. |
  318.     text
  319.         " read updated text and store it"
  320.         ^ text <- <165 panePtr 1>
  321. |
  322.     selectedText
  323.         " read selected text and store it"
  324.         selectRange <- self getSelectionRange.
  325.         ^ text <- <165 panePtr 2>
  326. |
  327.     replaceAllTextWith: newText
  328.         <165 panePtr 3 newText>
  329. |
  330.     clearAllText
  331.         <165 panePtr 4>
  332. |
  333.     print: text
  334.         <166 panePtr text>
  335. |
  336.     draw
  337.         "redraw pane"
  338.         <168 4 panePtr>.
  339.         <168 3 panePtr>.
  340.         <168 5 panePtr>
  341. |
  342.     saveContentsTo: aFileName withType: aFileType
  343.     | f |
  344.         f <- File new;
  345.             name: aFileName;
  346.             open: 'wb' withType: aFileType.
  347.         watchCursor show.
  348.         <206 panePtr 1 (f number)>.
  349.         f close.
  350.         smalltalk setDefaultCursor
  351. |
  352.     saveContents: fileType        | fname |
  353.         fname <- smalltalk askNewFile: 'Text file:'.
  354.         (fname notNil) ifTrue: [
  355.             self saveContentsTo: fname withType: fileType.
  356.             ^ true
  357.         ]
  358.         ifFalse: [
  359.             ^ false
  360.         ]
  361. |
  362.     loadContentsFrom: aFileName | f |
  363.         f <- File new;
  364.             name: aFileName;
  365.             open: 'rb'.
  366.         watchCursor show.
  367.         <206 panePtr 0 (f number)>.
  368.         f close.
  369.         smalltalk setDefaultCursor
  370. |
  371.     loadContents: fileType        | fname |
  372.         fname <- smalltalk askFile: 'Text file:' withFilter: fileType.
  373.         (fname notNil) ifTrue: [
  374.             self loadContentsFrom: fname.
  375.             ^ true
  376.         ]
  377.         ifFalse: [
  378.             ^ false
  379.         ]
  380. |
  381.     getSelectionRange
  382.         " Return the current selection range as a point where x = start and y = end
  383.           of range "
  384.         ^ <165 panePtr 9>
  385. |
  386.     setSelectionRangeFrom: startCharPos to: endCharPos
  387.         " set the selection range to the given start and end character positions "
  388.         <165 panePtr 8 startCharPos endCharPos>
  389. |
  390.     scrollToSelection
  391.         " Ensure that the current selection is visible within the text pane"
  392.         <165 panePtr 10>
  393. |
  394.     font: aFontName
  395.         fontName <- aFontName.
  396.         <165 panePtr 5 aFontName>
  397. |
  398.     fontSize: aNumber
  399.         fontSize <- aNumber.
  400.         <165 panePtr 6 aNumber>
  401. |
  402.     typeFace: aNumber    " 1 - plain, 2 - bold, 3 - italic, 4 - underline "
  403.         typeFace <- aNumber.
  404.         <165 panePtr 7 aNumber>
  405. |
  406.     saveState
  407.         self text.
  408.         selectRange <- self getSelectionRange
  409. |
  410.     restoreState
  411.         " Restore the state of this pane after loading a new image file and 
  412.           re-draw any text "
  413.         panePtr <- < 168 1 (parentWindow number) type 
  414.                         (bounds upperLeft x) 
  415.                         (bounds upperLeft y)
  416.                         (bounds bottomRight x)
  417.                         (bounds bottomRight y) 
  418.                         (sizing x) (sizing y) >.
  419.         (fontName notNil) ifTrue: [
  420.             self font: fontName
  421.         ].
  422.         (fontSize notNil) ifTrue: [
  423.             self fontSize: fontSize
  424.         ].
  425.         (typeFace notNil) ifTrue: [
  426.             self typeFace: typeFace
  427.         ].
  428.         self print: text.
  429.         (selectRange notNil) ifTrue: [
  430.             ((selectRange x) ~= (selectRange y)) ifTrue: [
  431.                 self setSelectionRangeFrom: (selectRange x) to: (selectRange y).
  432.                 self scrollToSelection
  433.             ]
  434.         ]
  435. ]
  436.  
  437. Methods SelectListPane 'all'
  438.     isTextPane
  439.         ^ false
  440. |
  441.     attachTo: aWindow withSizing: aPoint
  442.         panePtr <- super attachTo: aWindow withType: 2 andSizing: aPoint
  443. |
  444.     text: t
  445.         text <- t.
  446.         self print: text
  447. ]
  448.  
  449. Methods GraphicsPane 'all'
  450.     isTextPane
  451.         ^ false
  452. |
  453.     attachTo: aWindow withSizing: aPoint
  454.         panePtr <- super attachTo: aWindow withType: 3 andSizing: aPoint
  455. |
  456.     startDrawing
  457.         <168 4 panePtr>
  458. |
  459.     endDrawing
  460.         <168 5 panePtr>
  461. |
  462.     draw
  463.         " done by subclasses "
  464.         ^ nil
  465. |
  466.     at: x and: y print: text
  467.         <190 x y text>
  468. |
  469.     saveState
  470.         " Should save graphics in some way that allows them to be
  471.           easily restored later "
  472.         ^ nil
  473. |
  474.     restoreState
  475.         " Restore the state of this pane after loading a new image file and 
  476.           re-draw any graphics "
  477.         super restoreState.
  478.         self draw
  479. ]
  480.  
  481. Methods Menu 'all'
  482.     new
  483.         numItems <- 0.
  484.         items <- Array new: 0.
  485.         itemtitles <- Array new: 0.
  486.         enablestatus <- Array new: 0.
  487.         (1 to: 15) do: [:i | (menus at: i) isNil
  488.             ifTrue: [ menus at: i put: self.
  489.                     number <- i.  ^ self ] ]
  490. |
  491.     number
  492.         ^ number
  493. |
  494.     menuPtr
  495.         ^ menuPtr
  496. |
  497.     addSeparator        "Note: Macintosh specific"
  498.         self addItem: '-' action: [ ^ nil ].
  499.         self disableItem: numItems
  500. |
  501.     addItem: name action: aBlock
  502.         items <- items with: aBlock.
  503.         itemtitles <- itemtitles with: name.
  504.         enablestatus <- enablestatus with: true.
  505.         <181 menuPtr name nil>.
  506.         numItems <- numItems + 1
  507. |
  508.     removeItem: anItemNumber
  509.         (anItemNumber to: (numItems - 1)) do: [:i |     "Shift up array elements to close gap"
  510.             items at: i put: (items at: (i + 1)).
  511.             itemtitles at: i put: (itemtitles at: (i + 1)).
  512.             enablestatus at: i put: (enablestatus at: (i + 1))
  513.         ].
  514.         <184 menuPtr 2 anItemNumber>.
  515.         numItems <- numItems - 1
  516. |
  517.     enableItem: n
  518.         enablestatus at: n put: true.
  519.         <182 menuPtr n 1 1>
  520. |
  521.     disableItem: n
  522.         enablestatus at: n put: false.
  523.         <182 menuPtr n 1 0>
  524. |
  525.     selectItem: n inWindow: w
  526.         " execute the selected menu item "
  527.         (items at: n) value: w
  528. |
  529.     title: aString
  530.         " give the title to a menu item"
  531.         title <- aString
  532. |
  533.     create
  534.         "create menu"
  535.         menuPtr <- <180 number title 0>            "Method changed for v3.1.3"
  536. |
  537.     dispose
  538.         <184 menuPtr 1>
  539. |
  540.     restoreItems
  541.         " Add all the existing items and set status accordingly "
  542.         (1 to: items size) do:
  543.             [:i | <181 menuPtr (itemtitles at: i) nil>.
  544.                 (enablestatus at: i) 
  545.                     ifFalse: [ self disableItem: i]]
  546. |
  547.     restoreState
  548.         " Restore the state of this menu after loading a new image file "
  549.         self create.
  550.         self restoreItems
  551. ]
  552.  
  553. Methods PopUpMenu 'all'
  554.     new                        "Super method overridden for v3.1.3"
  555.         numItems     <- 0.
  556.         items        <- Array new: 0.
  557.         itemtitles   <- Array new: 0.
  558.         enablestatus <- Array new: 0.
  559. |
  560.     create                    "Method changed for v3.1.3"
  561.         "create menu"
  562.         menuPtr <- <180 nextPopMenuNum title 1>.
  563.         number  <- nextPopMenuNum.
  564.         nextPopMenuNum <- nextPopMenuNum + 1
  565. |
  566.     popUpAt: aPoint | sel item |
  567.         smalltalk setDefaultCursor.
  568.         sel <- <183 menuPtr (aPoint y) (aPoint x)>.
  569.         (sel ~= 0) ifTrue: [
  570.             item <- items at: sel.
  571.             item value
  572.         ]
  573. |
  574.     restoreState
  575.         " Restore the state of this pop-up menu after loading a new image file "
  576.         self create.
  577.         self restoreItems
  578. ]
  579.  
  580. Methods EventManager 'all'
  581.     new
  582.     "Create an array containing methods to be executed on receiving each event"
  583.         responses <- Array new: 24.
  584.         responses at: 1  put: [:w | w activate ].
  585.     " Where key presses are concerned, TextEdit now does the hard work. So, 
  586.       unless anyone has a better idea, we will ignore key presses for now. "
  587.         responses at: 2  put: [:w | w <- nil ].
  588.     "    responses at: 2  put: [:w | w charTyped: (Char new; value: <171 4>) ]."
  589.         responses at: 3  put: [:w | w command: <171 9> ].
  590.         responses at: 4  put: [:w | 
  591.                         w mouseDownAt: self mouseLocation button: (self mouseButton) ].
  592.         responses at: 5  put: [:w | w mouseMoveTo: self mouseLocation ].
  593.         responses at: 6  put: [:w | w mouseUpAt: self mouseLocation ].
  594.         responses at: 7  put: [:w | self eventMenu 
  595.             selectItem: self menuItem inWindow: w ].
  596.         responses at: 8  put: [:w | w reSized ].
  597.         responses at: 9  put: [:w | w moved ].
  598.         responses at: 10 put: [:w | smalltalk updateWindows ].
  599.         self newPartTwo
  600. |
  601.     newPartTwo
  602.     "Continuation of the above method due to limits on bytecode array sizes"
  603.         responses at: 11 put: [:w | scheduler quit ].            "Was timer event"
  604.         responses at: 12 put: [:w | w deactivate ].
  605.         responses at: 13 put: [:w | smalltalk processEvent ].   "Externally generated event (AppleEvent)"
  606.         responses at: 14 put: [:w | w deactivate ].  "Non-ASCII key event"
  607.         responses at: 15 put: [:w | w deactivate ].  "Lost selection"
  608.         responses at: 16 put: [:w | w close ]
  609. |
  610.     eventWindow | w |                "Which window is event from?"
  611.     
  612.         "Changed to allow for legitimate cases when window is not"
  613.         "found (e.g. menu selection made with no open windows or a window"
  614.         "has been selected that is not ours"
  615.         
  616.         w <- <171 1>.                            
  617.         (w = 0) ifTrue: [
  618.             ^ 0
  619.         ]
  620.         ifFalse: [    
  621.             ^ windows at: w
  622.         ]    
  623. |
  624.     eventMenu | m |
  625.         ^ menus at: <171 2>.            "Which menu is event from?"
  626. |
  627.     menuItem
  628.         ^ <171 3>
  629. |
  630.     mouseLocation
  631.         " return the current location of the mouse "
  632.         ^ <172 1>
  633. |
  634.     mouseButton
  635.         " Return the number of the mouse button pressed "
  636.         ^ <171 6>
  637. |
  638.     mouseClicks
  639.         " Return the number of clicks of the mouse button - added for v3.1.2"
  640.         ^ <171 7>
  641. |
  642.     isDoubleClick
  643.         " Return true if a double click has been detected - added for v3.1.2"
  644.         (self mouseClicks = 2) ifTrue: [
  645.             ^ true
  646.         ].
  647.         ^ false
  648. |
  649.     execute        | i w |
  650.         " process one event "
  651.         i <- <170>. (i = 0) 
  652.         ifFalse: [             "Changed to allow for eventWindow returning zero"
  653.             w <- self eventWindow.
  654.             (w = 0) ifTrue: [ 
  655.                 (i = 11) ifTrue: [    "Trap quit command"
  656.                     (responses at: i) value: nil         
  657.                 ].
  658.                 (i = 7) ifTrue: [    "Trap menu selection with no open windows"
  659.                     (responses at: i) value: nil         
  660.                 ]                    "Other possibility is that window is not ours"
  661.             ]                         " so we ignore it"
  662.             ifFalse: [
  663.                 (responses at: i) value: self eventWindow 
  664.             ]
  665.         ]
  666. ]
  667.  
  668. Methods UserInterface 'all'
  669.     makeSystemMenu | f n |                    " Changed for v3.1.3"
  670.         systemMenu isNil ifTrue: [ 
  671.             systemMenu <- Menu new; title: 'System'; create.
  672.             systemMenu addItem: 'Browser' 
  673.                        action: [:w | Browser new; open ];
  674.                 addSeparator;
  675.                 addItem: 'Interpret File...'
  676.                     action: [:w | 
  677.                         f <- (smalltalk askFile: 'file name:').
  678.                         (f notNil) ifTrue: [
  679.                             smalltalk interpretFile: f
  680.                         ]
  681.                     ];
  682.                  addItem: 'Save image...'
  683.                     action: [:w | [ 
  684.                         windows do: [:w | w notNil ifTrue: [ w saveState ]].
  685.                         f <- (smalltalk askNewFile: 'Image file:').
  686.                         watchCursor show.
  687.                         smalltalk saveImage: f; setDefaultCursor
  688.                     ] fork ].
  689.                 self makeSystemMenu2
  690.         ]
  691. |    
  692.     makeSystemMenu2
  693.         systemMenu addSeparator;
  694.             addItem: 'Save Text...'
  695.                 action: [:w | [ (w mainPane) saveContents: 1 ] fork ];
  696.             addItem: 'Open Text...'
  697.                 action: [:w | [ (w mainPane) loadContents: 1 ] fork ];
  698.             addSeparator;
  699.             addItem: 'Print It'
  700.                 action: [:w | 
  701.                 [ (w mainPane) print: ((w mainPane) selectedText value asString) , 
  702.                   newLine ] fork ];
  703.             addItem: 'Do It'
  704.                 action: [:w | [ (w mainPane) selectedText execute ] fork ];
  705.             addSeparator;
  706.             addItem: 'Restore Workspace'
  707.                 action: [:w | [ self restoreWorkspace ] fork ].
  708. |
  709.     makeWindowsMenu
  710.         windowsMenu    <- Menu new; title: 'Windows'; create.
  711.         nextItemNumber <- 0.
  712.         itemList       <- Array new: 15
  713. |
  714.     addToWindowsMenu: aWindow
  715.         (nextItemNumber == 0) ifFalse: [
  716.             ((itemList at: nextItemNumber) == aWindow) ifTrue: [
  717.                 ^ nil                             " Already there..."
  718.             ]
  719.         ].
  720.         windowsMenu addItem: (aWindow title) 
  721.             action: [:w | (itemList at: (eventManager menuItem)) select ].
  722.         nextItemNumber <- nextItemNumber + 1.
  723.         itemList at: nextItemNumber put: aWindow.
  724.         self checkSystemMenu
  725. |
  726.     removeFromWindowsMenu: aWindow    | wmi |
  727.         (1 to: nextItemNumber) do: [ :i |        "Find the window in the list"
  728.             ((itemList at: i) == aWindow) ifTrue: [
  729.                 wmi <- i
  730.             ]
  731.         ].
  732.         windowsMenu removeItem: wmi.
  733.         (wmi to: nextItemNumber - 1) do: [:i |     "Shift up array elements to close gap"
  734.             itemList at: i put: (itemList at: (i + 1))
  735.         ].
  736.         nextItemNumber <- nextItemNumber - 1.
  737.         self checkSystemMenu
  738. |
  739.     makeWorkspace " Functionality moved to class WorkspaceWindow - v3.1.2 "
  740.         workspace <- WorkspaceWindow new.
  741.         workspace attachMenu: systemMenu; attachMenu: windowsMenu.
  742.         systemMenu disableItem: 12.
  743. |
  744.     saveWorkspace " Added for v3.1.2 "
  745.         saveWS    <- workspace.
  746.         workspace <- nil.
  747.         printer   <- nil.
  748. |
  749.     restoreWorkspace " Added for v3.1.2 "
  750.         workspace <- saveWS.
  751.         workspace restoreWorkspace.
  752.         printer <- workspace mainPane.
  753. |
  754.     checkSystemMenu
  755.     " Disable certain menu items when there are no windows open. Enable
  756.       them when there are. Invoked whenever windows are opened or closed.
  757.       - added for v3.1.1"
  758.         (nextItemNumber = 0) ifTrue: [
  759.             systemMenu  disableItem: 6;
  760.                          disableItem: 7;
  761.                          disableItem: 9;
  762.                          disableItem: 10;
  763.                         enableItem:  12
  764.         ]
  765.         ifFalse: [
  766.             systemMenu  enableItem:  6;
  767.                         enableItem:  7;
  768.                         enableItem:  9;
  769.                         enableItem:  10.
  770.             workspace isNil ifTrue: [
  771.                 systemMenu enableItem: 12
  772.             ]
  773.             ifFalse: [
  774.                 systemMenu disableItem: 12
  775.             ]
  776.         ]
  777. ]
  778.  
  779. Methods Smalltalk 'doit'
  780.     error: aString    | ew |
  781.         " print a message, and remove current process "
  782.         " scheduler currentProcess trace. "
  783.         self showMessage: aString.
  784.         (scheduler currentProcess) terminate
  785. ]
  786.  
  787. Methods Scheduler 'get commands'
  788.     initialize
  789.         (workspace isNil) ifTrue: [
  790.             watchCursor fetchNamedCursor: 'watch'.
  791.             userInterface makeSystemMenu.
  792.             userInterface makeWindowsMenu.
  793.             userInterface makeWorkspace
  794.         ].
  795.         printer      <- workspace mainPane.
  796.         eventManager <- EventManager new.
  797.         scheduler addProcess: eventManager
  798. |
  799.     quit
  800.         " all done - really quit "
  801.         " should probably verify first "
  802.         notdone <- false
  803. ]
  804. *
  805. * initialization code
  806. * this is executed once, by the initial image maker
  807. *
  808. *
  809. Methods UndefinedObject 'initial image'
  810.     createGlobals
  811.         " create global variables in initial image "
  812.         true      <- True new.
  813.         false     <- False new.
  814.         smalltalk <- Smalltalk new.
  815.         files     <- Array new: 15.
  816.         classes   <- Dictionary new.        " create a dictionary of classes "
  817.         symbols binaryDo: [:x :y | 
  818.             (y class == Class)
  819.                 ifTrue: [ classes at: x put: y ] ].
  820.         self createGlobalsPart2
  821. |
  822.     createGlobalsPart2
  823.         printer         <- nil.
  824.         windows         <- Array new: 15.
  825.         menus           <- Array new: 15.
  826.         scheduler       <- Scheduler new.
  827.         userInterface   <- UserInterface new.
  828.         eventManager    <- nil.
  829.         workspace       <- nil.
  830.         activeWindow    <- nil.
  831.         nextBrowserNum  <- 1.
  832.         nextWkSpaceNum  <- 1.
  833.         newLine         <- 13 asCharacter.
  834.         watchCursor     <- Cursor new.
  835.         systemMenu        <- nil.
  836.         windowsMenu     <- nil. 
  837.         nextPopMenuNum  <- 0                "Global added for v3.1.3"
  838. |
  839.     initialize    | aBlock |
  840.         " initialize the initial object image "
  841.         self createGlobals.
  842.         " create the initial system process "
  843.         " note the delayed recursive call "
  844.         aBlock <- [ files do: [:f | f notNil ifTrue: [ f open ]].
  845.                 menus do: [:m | m notNil ifTrue: [ m restoreState ]].
  846.                 windows do: [:w | w notNil ifTrue: [ w restoreState ]].
  847.                 systemProcess <- aBlock newProcess.
  848.                 scheduler run ].
  849.         systemProcess <- aBlock newProcess.
  850.         File new;
  851.             name: 'systemImage';
  852.             open: 'wb' withType: 2;
  853.             saveImage;
  854.             close
  855. ]
  856.  
  857. Methods String 'test'
  858.     print
  859.         ^ printer print: self
  860. ]
  861.  
  862. Methods Smalltalk 'interface'
  863.     getVersion                            "Added for v3.1.3"
  864.         ^ <254>
  865. |
  866.     showMessage: aString                "Added for v3.1.2"
  867.         ^ <204 aString>
  868. |
  869.     getPrompt: aString
  870.         ^ <201 aString ''>
  871. |
  872.     askNewFile: prompt
  873.         " ask for a new file name "
  874.         ^ <203 prompt '' 1 0>
  875. |    
  876.     askFile: prompt
  877.         "ask for a file name but don't filter out unwanted file types"
  878.         ^ <203 prompt '' 0 0>
  879. |
  880.     askFile: prompt    withFilter: filter    | i |
  881.         "ask for a file name, filtering out all types but 'filter'. Filter
  882.          should be 1 or 2 according to the three available file types: 
  883.              1 - Text (including saved workspaces)
  884.              2 - System Image "
  885.         ^ <203 prompt '' 0 filter>
  886. |
  887.     inquire: aString
  888.         ^ <202 aString 1>
  889. |
  890.     updateWindows            "Re-draw all windows"
  891.         windows do: [ :win |
  892.             (win notNil)
  893.             ifTrue: [
  894.                 win drawEvent
  895.             ]
  896.         ]
  897. |
  898.     updateClassDictionary
  899.     " Update the class dictionary. It's a bit wasteful 
  900.       creating a new Dictionary object every time, but
  901.       the alternative is to check each class to see if
  902.       it's new or not...."
  903.         classes <- Dictionary new.
  904.         symbols binaryDo: [:x :y | 
  905.             (y class == Class) ifTrue: [ 
  906.                 classes at: x put: y 
  907.             ] 
  908.         ]
  909. |
  910.     getMaxScreenArea        "Return a rect representing the max available screen area"
  911.         ^ <167>
  912. |
  913. "
  914.   processEvent: Process externally generated events 
  915.   - only event for now is Open Document so we do no event type checks.
  916. "
  917.     processEvent    | fullPath ft  mp |            "Changed for v3.1.3"    
  918.         fullPath <- <207>.        " Get info from event - a file type and a full path "
  919.         (fullPath notNil) ifTrue: [
  920.             ft       <- (fullPath copyFrom: 1 to: 1) asInteger.
  921.             fullPath <- fullPath copyFrom: 2 to: (fullPath size).
  922.             (ft = 2) ifTrue: [
  923.                 self showMessage: 
  924.                 'Cannot load new System Image whilst application is still running'
  925.             ]
  926.             ifFalse: [
  927.                 self processDroppedFile: fullPath
  928.             ]
  929.         ]
  930. |
  931.     processDroppedFile: fullPath | s |            "Method added for v3.1.3"
  932.         s <- fullPath copyFrom: ((fullPath size) - 2) to: (fullPath size).
  933.         (s = '.st') ifTrue: [
  934.             self interpretFile: fullPath.
  935.             ^ nil
  936.         ].
  937.         (activeWindow isNil) ifTrue: [
  938.             userInterface makeWorkspace
  939.         ].
  940.         mp <- activeWindow mainPane.
  941.         (mp isTextPane) ifTrue: [
  942.             mp loadContentsFrom: fullPath
  943.         ]
  944.         ifFalse: [
  945.             self showMessage: 'Cannot load text file into non-text window pane'
  946.         ].
  947.         ^ nil
  948. |
  949.     interpretFile: aFileName                    "Method added for v3.1.3"
  950.         watchCursor show.
  951.         File new; fileIn: aFileName.
  952.         self updateClassDictionary; setDefaultCursor
  953. ]
  954.  
  955. Methods Point 'drawing'
  956.     moveTo
  957.         <192 2 (self x) (self y)>
  958. |
  959.     drawPixel
  960.         <192 3 (self x) (self y)>
  961. |
  962.     lineTo
  963.         <192 1 (self x) (self y)>
  964. ]
  965.  
  966. Methods Rectangle 'drawing'
  967.     frame
  968.         <194 1 left top right bottom>
  969. |
  970.     paint
  971.         <194 2 left top right bottom>
  972. |
  973.     erase
  974.         <194 3 left top right bottom>
  975. |
  976.     invert
  977.         <194 4 left top right bottom>
  978. |
  979.     shade: aPercent
  980.         <195 1 left top right bottom aPercent>
  981. ]
  982.  
  983. Methods Smalltalk 'beep'
  984.     beep
  985.         <205>
  986. ]
  987.  
  988. Methods Circle 'drawing'
  989.     frame
  990.         <193 1 (center x) (center y) radius>
  991. ]
  992.  
  993. Methods Cursor 'all'
  994.     "
  995.     The valid cursor names are:
  996.         ibeam      - standard text-editing cursor
  997.         cross      - cross-hairs
  998.         plus       - blocky '+' sign
  999.         watch      - standard 'busy' cursor
  1000.         arrow      - default
  1001.         ClosedHand - a closed hand
  1002.         OpenHand   - an open hand 'dragging' cursor
  1003.         Pen        - a pen symbol
  1004.     The last three are defined in the resource fork. Extra cursors maybe added
  1005.     to the resource file and referenced by name in the same way.
  1006.     "
  1007.     fetchNamedCursor: aCursorName
  1008.         cursPtr <- <164 1 aCursorName>
  1009. |
  1010.     show
  1011.         <164 2 cursPtr>
  1012. ]
  1013.  
  1014. Methods Smalltalk 'cursor'
  1015.     setDefaultCursor
  1016.         <164 3>
  1017. ]
  1018.